home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 February
/
EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso
/
earcd
/
comm2
/
termsorc.lha
/
Extras
/
Source
/
gtlayout-source.lha
/
LTP_LayoutMenu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-24
|
10KB
|
424 lines
/* GadTools layout toolkit
**
** Copyright © 1993-1995 by Olaf `Olsen' Barthel
** Freely distributable.
**
** :ts=4
*/
#include "gtlayout_global.h"
#ifdef DO_MENUS
/* LTP_LayoutMenu(RootMenu *Root,WORD ExtraFront,WORD ExtraSpace):
*
* Layout the menus, menu items and submenu items.
*/
BOOLEAN __regargs
LTP_LayoutMenu(RootMenu *Root,WORD ExtraFront,WORD ExtraSpace)
{
WORD MenuLeft,
ItemTop,
ItemWidth,
ItemShift,
CommandWidth,
Width;
MenuNode *Menu;
ItemNode *Item,*FirstItem = NULL,*LastItem;
BOOLEAN Correction;
// That one's simple
for(MenuLeft = ExtraFront, Menu = (MenuNode *)Root -> MenuList . mlh_Head ; Menu -> Node . mln_Succ ; Menu = (MenuNode *)Menu -> Node . mln_Succ)
{
Menu -> Menu . LeftEdge = MenuLeft;
MenuLeft += Menu -> Menu . Width + ExtraSpace;
}
// Now run down the list of items
for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
// Hit a submenu item?
if(Item -> Flags & ITEMF_FirstSub)
{
ItemNode *FirstSub,*LastSub,*Sub;
WORD SubTop = 0,
SubWidth = 0;
WORD CommandWidth = 0;
// This is where we started
FirstSub = Item;
// Now determine the widest entry and
// line them up below one another
for(Sub = FirstSub ; Sub -> Node . mln_Succ && (Sub -> Flags & ITEMF_IsSub) ; Sub = (ItemNode *)Sub -> Node . mln_Succ)
{
LastSub = Sub;
if(Sub -> Item . Width > SubWidth)
SubWidth = Sub -> Item . Width;
if((Width = LTP_GetCommandWidth(Root,Sub)) > CommandWidth)
CommandWidth = Width;
Sub -> Item . TopEdge = SubTop;
SubTop += Sub -> Item . Height;
}
SubWidth += 4 + CommandWidth;
// In the second pass, make all entries
// use the same width
for(Sub = FirstSub ; ; Sub = (ItemNode *)Sub -> Node . mln_Succ)
{
// Indent the entries that need it
if(Sub -> Item . Flags & CHECKIT)
((struct IntuiText *)Sub -> Item . ItemFill) -> LeftEdge += 2 + Root -> CheckWidth;
Sub -> Item . Width = SubWidth;
// Adapt the separator bar size
if(Sub -> Flags & ITEMF_IsBar)
((struct Image *)Sub -> Item . ItemFill) -> Width = Sub -> Item . Width - 4;
else
{
// Take care of command keys
if(Sub -> Flags & ITEMF_Command)
{
struct IntuiText *Command = ((struct IntuiText *)Sub -> Item . ItemFill) -> NextText;
Command -> LeftEdge = Sub -> Item . Width - (IntuiTextLength(Command) + 2);
}
}
// In the next iteration, continue after the last
// submenu item
if(Sub == LastSub)
{
Item = Sub;
break;
}
}
DB(kprintf("last sub |%s|\n",((struct IntuiText *)Item -> Item . ItemFill) -> IText));
}
else
{
// Start a new menu?
if(!FirstItem)
{
// This is where we started
FirstItem = Item;
// Reset the data
ItemTop = ItemWidth = ItemShift = CommandWidth = 0;
}
// Line up the entries in a column
Item -> Item . TopEdge = ItemTop;
ItemTop += Item -> Item . Height;
// Search for the widest entry
if(Item -> Item . Width > ItemWidth)
ItemWidth = Item -> Item . Width;
// Search for the widest command sequence
if((Width = LTP_GetCommandWidth(Root,Item)) > CommandWidth)
CommandWidth = Width;
// This is for submenu items which will get
// indented by this amount
if(Item -> Item . Width > ItemShift)
ItemShift = Item -> Item . Width;
}
// Is this the last item for this menu?
if(Item -> Flags & ITEMF_LastItem)
{
ItemWidth += 4 + CommandWidth;
// Restart and layout all the items in this menu
for(Item = FirstItem ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
// Indent submenu items
if(Item -> Flags & ITEMF_IsSub)
Item -> Item . LeftEdge += ItemShift + 6;
else
{
// Indent items as necessary
if(Item -> Item . Flags & CHECKIT)
((struct IntuiText *)Item -> Item . ItemFill) -> LeftEdge += 2 + Root -> CheckWidth;
Item -> Item . Width = ItemWidth;
// Adapt the separator bar size
if(Item -> Flags & ITEMF_IsBar)
((struct Image *)Item -> Item . ItemFill) -> Width = Item -> Item . Width - 4;
else
{
// Take care of submenu item indicators and
// command sequences
if(Item -> Flags & (ITEMF_Command | ITEMF_HasSub))
{
struct IntuiText *Command = ((struct IntuiText *)Item -> Item . ItemFill) -> NextText;
Command -> LeftEdge = Item -> Item . Width - (IntuiTextLength(Command) + 2);
}
}
}
// Abort if this is the last item for this menu
if(Item -> Flags & ITEMF_LastItem)
break;
}
DB(kprintf("last item |%s|\n",((struct IntuiText *)Item -> Item . ItemFill) -> IText));
// The next iteration will start a new menu
FirstItem = NULL;
}
}
// Calculate the effective positions
LTP_AdjustMenuPosition(Root);
Correction = FALSE;
// We start by chopping down the menus
for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
// That's where we start
if(!FirstItem)
FirstItem = Item;
// Skip submenu items
if(!(Item -> Flags & ITEMF_IsSub))
LastItem = Item;
// Did we reach the end of the menu?
if(Item -> Flags & ITEMF_LastItem)
{
DB(kprintf("chopping |%s| -> |%s|\n",((struct IntuiText *)FirstItem -> Item . ItemFill) -> IText,((struct IntuiText *)LastItem -> Item . ItemFill) -> IText));
// Chop down the menus
Correction |= LTP_CorrectItemList(Root,FirstItem,LastItem);
FirstItem = NULL;
}
}
if(Correction)
{
Correction = FALSE;
// Recalculate the positions
LTP_AdjustMenuPosition(Root);
}
// Next we shift the menus around to make them fit
for(Menu = (MenuNode *)Root -> MenuList . mlh_Head ; Menu -> Node . mln_Succ ; Menu = (MenuNode *)Menu -> Node . mln_Succ)
{
MenuLeft = Menu -> Menu . LeftEdge + 4 + Menu -> Width + 4;
// Does it cross the right screen border?
if(MenuLeft > Root -> Screen -> Width)
{
// Is the menu wider than the screen?
if(4 + Menu -> Width + 4 > Root -> Screen -> Width)
{
DB(kprintf("too wide\n"));
return(FALSE);
}
else
{
WORD Left = MenuLeft - Root -> Screen -> Width + 1;
// Move up
for(Item = (ItemNode *)((ULONG)Menu -> Menu . FirstItem - sizeof(struct MinNode)) ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
if(!(Item -> Flags & ITEMF_IsSub))
Item -> Item . LeftEdge -= Left;
if(Item -> Flags & ITEMF_LastItem)
break;
}
Correction = TRUE;
}
}
}
if(Correction)
{
Correction = FALSE;
// Recalculate the positions
LTP_AdjustMenuPosition(Root);
}
// Now deal with the submenus
for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
// Only submenu items, please
if(Item -> Flags & ITEMF_FirstSub)
{
ItemNode *Here;
// Find the first and the last entry
for(Here = Item ; Here -> Node . mln_Succ ; Here = (ItemNode *)Here -> Node . mln_Succ)
{
if(!(Here -> Flags & ITEMF_IsSub))
break;
else
LastItem = Here;
}
DB(kprintf("2) chopping |%s| -> |%s|\n",((struct IntuiText *)Item -> Item . ItemFill) -> IText,((struct IntuiText *)LastItem -> Item . ItemFill) -> IText));
// Chop down the submenus
Correction |= LTP_CorrectItemList(Root,Item,LastItem);
}
}
if(Correction)
{
Correction = FALSE;
LTP_AdjustMenuPosition(Root);
}
// Almost finished, now shift the submenus around
for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
// Did we hit a submenu?
if(Item -> Flags & ITEMF_HasSub)
{
ItemNode *Here = (ItemNode *)((ULONG)Item -> Item . SubItem - sizeof(struct MinNode));
// Does this one also cross the right screen border?
if((MenuLeft = Here -> Left + 4 + Here -> Item . Width + 4) > Root -> Screen -> Width)
{
WORD Left = MenuLeft - Root -> Screen -> Width;
// This shouldn't be wider than the screen, but...
if(Here -> Left - Left < Item -> Left + 10)
{
DB(kprintf("sub too wide\n"));
return(FALSE);
}
else
{
DB(kprintf("3) shifting...\n"));
// Shift the menu around
do
{
if(!(Here -> Flags & ITEMF_IsSub))
break;
else
{
Here -> Item . LeftEdge -= Left;
Correction = TRUE;
if(Here -> Flags & ITEMF_LastItem)
break;
Here = (ItemNode *)Here -> Node . mln_Succ;
}
}
while(Here -> Node . mln_Succ);
}
}
}
}
// The last step; see if the alignment stuff worked
if(Correction)
LTP_AdjustMenuPosition(Root);
// First check the menus
for(Menu = (MenuNode *)Root -> MenuList . mlh_Head ; Menu -> Node . mln_Succ ; Menu = (MenuNode *)Menu -> Node . mln_Succ)
{
// Does it cross the screen borders?
if((MenuLeft = Menu -> Menu . LeftEdge + 4 + Menu -> Width + 4) > Root -> Screen -> Width || Menu -> Menu . LeftEdge < 0)
return(FALSE);
}
// Now check the submenus
for(Item = (ItemNode *)Root -> ItemList . mlh_Head ; Item -> Node . mln_Succ ; Item = (ItemNode *)Item -> Node . mln_Succ)
{
// Did we hit a submenu?
if(Item -> Flags & ITEMF_HasSub)
{
ItemNode *Here = (ItemNode *)((ULONG)Item -> Item . SubItem - sizeof(struct MinNode));
if(Here -> Left + Here -> Width > Root -> Screen -> Width)
return(FALSE);
}
}
LTP_FillMenu(&Root -> Menu);
return(TRUE);
}
#endif /* DO_MENUS */